﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;

namespace ITAP.ShprossesBuilder.Modelling.Components
{
    [Serializable]
    public class ModelCellRepository
    {
        private double[] maxHeight;
        private double[] maxWidth;

        public int RowsCount
        {
            get
            {
                return this.cells.Count;
            }
        }

        private int columnsCount;
        public int ColumnsCount
        {
            get
            {
                return columnsCount;
            }
        }

        private List<List<ModelCell>> cells;

        public List<List<ModelCell>> Cells
        {
            get { return cells; }
        }

        public ModelCellRepository()
        {
            cells = new List<List<ModelCell>>();
            
        }      

        private void Recalculate(int horizontalIndex, int verticalIndex)
        {
            int newCellsCount;
            if(horizontalIndex >= this.ColumnsCount)
            {
                if (verticalIndex >= this.RowsCount)
                {
                    List<ModelCell> newRow = new List<ModelCell>();
                    for (int j = 0; j <= horizontalIndex; j++)
                    {
                        newRow.Add(null);
                    }
                    this.cells.Add(newRow);
                }
                foreach (List<ModelCell> row in this.cells)
                {
                    newCellsCount = horizontalIndex - row.Count + 1;
                    for (int i = 0; i < newCellsCount; i++)
                        row.Add(null);
                }
                
                this.columnsCount = horizontalIndex + 1;
            }

            if (verticalIndex >= this.RowsCount)
            {
                newCellsCount = verticalIndex - this.cells.Count + 1;
                for (int i = 0; i < newCellsCount; i++)
                {
                    List<ModelCell> newRow = new List<ModelCell>();
                    for (int j = 0; j < this.columnsCount; j++)
                    {
                        newRow.Add(null);
                    }
                    cells.Add(newRow);
                }
            }

        }

        public double GetTotalCellsWidth()
        {
            double result = 0;
            double[] width = new double[this.ColumnsCount];
            for (int i = 0; i < this.cells.Count; i++)
            {
                for (int j = 0; j < this.ColumnsCount; j++)
                {
                    if (this.cells[i][j] != null && width[j] == 0)
                        width[j] = this.cells[i][j].BoundingBox.Width;
                }
            }
            foreach (double value in width)
                result += value;

            return result;
        }

        public double GetTotalCellsHeight()
        {
            double result = 0;
            double[] height = new double[this.RowsCount];
            for (int i = 0; i < this.cells.Count; i++)
            {
                for (int j = 0; j < this.ColumnsCount; j++)
                {
                    if (this.cells[i][j] != null && height[i] == 0)
                        height[i] = this.cells[i][j].BoundingBox.Height;
                }
            }
            foreach (double value in height)
                result += value;

            return result;
        }

        int cellCounter = 0;
        public void AddCell(ModelCell cell, int horizontalIndex, int verticalIndex)
        {
            
            //cell.SerialNumber = cellCounter + 1;
            cell.Name = "Модель " + cell.SerialNumber.ToString();
            cellCounter++;

            this.Recalculate(horizontalIndex, verticalIndex);
            cells[verticalIndex][horizontalIndex] = cell;
        }

        public void RecalculateCellsSizes()
        {
            maxHeight = new double[this.RowsCount];
            maxWidth = new double[this.ColumnsCount];

            for (int rowIter = 0; rowIter < this.cells.Count; rowIter++)
            {
                double maxRowHeight = this.GetMaxModelHeightInRow(rowIter);
                maxHeight[rowIter] = maxRowHeight;
                for (int columnIter = 0; columnIter < this.cells[rowIter].Count; columnIter++)
                {
                    ModelCell cell = this.cells[rowIter][columnIter];
                    if (cell == null)
                        continue;
                    double maxColumnWidth = this.GetMaxModelWidthInColumn(columnIter);
                    maxWidth[columnIter] = maxColumnWidth;
                    cell.BoundingBox = new RectangleF(0, 0,(float)maxColumnWidth, (float)maxRowHeight);
                }
            }
        }

        public void RecalculateModelPositions()
        {
            for (int rowIter = 0; rowIter < this.cells.Count; rowIter++)
            {
                this.RecalculateModelPositionsInRow(rowIter);
                for (int columnIter = 0; columnIter < this.cells[rowIter].Count; columnIter++)
                {
                    this.RecalculateModelPositionsInColumn(columnIter);
                }
            }
        }

        public void RecalculateModelPositionsInRow(int rowIndex)
        {
            foreach (ModelCell cell in cells[rowIndex])
            {
                if (cell != null)
                {
                    cell.MoveModelTo(cell.HorizontalModelAlign);
                    cell.MoveModelTo(cell.VerticalModelAlign);
                }
            }
        }

        public void RecalculateModelPositionsInColumn(int columnIndex)
        {
            foreach (List<ModelCell> row in cells)
            {
                if (row[columnIndex] != null)
                {
                    row[columnIndex].MoveModelTo(row[columnIndex].HorizontalModelAlign);
                    row[columnIndex].MoveModelTo(row[columnIndex].VerticalModelAlign);
                }
            }
        }

        public double GetMaxHeight(int rowIndex)
        {
            return this.maxHeight[rowIndex];
        }

        public double GetMaxWidth(int columnIndex)
        {
            return this.maxWidth[columnIndex];
        }

        private double GetMaxModelHeightInRow(int rowIndex)
        {
            double minY = double.MaxValue;
            double maxY = double.MinValue;

            foreach (ModelCell cell in cells[rowIndex])
            {
                if (cell == null)
                    continue;

                RectangleF cellBBox = cell.BoundingBox;
                RectangleF modelBBox = cell.Model.BoundingBox;
                if (cell == null)
                    continue;

                if (minY > modelBBox.Y)
                    minY = modelBBox.Y;
                if (maxY < modelBBox.Y + modelBBox.Height + cell.OffsetY)
                    maxY = modelBBox.Y + modelBBox.Height + cell.OffsetY;
            }
            if (double.IsInfinity(maxY - minY))
                return 0;
            else 
                return maxY - minY;
        }

        private double GetMaxModelWidthInColumn(int columnIndex)
        {
            double minX = double.MaxValue;
            double maxX = double.MinValue;

            for (int rowIter = 0; rowIter < this.cells.Count; rowIter++)
            {
                ModelCell cell = this.cells[rowIter][columnIndex];
                if (cell == null)
                    continue;

                RectangleF cellBBox = cell.Model.BoundingBox;
                RectangleF modelBBox = cell.Model.BoundingBox;

                if (minX > modelBBox.X)
                    minX = modelBBox.X;
                if (maxX < modelBBox.X + modelBBox.Width + cell.OffsetX)
                    maxX = modelBBox.X + modelBBox.Width + cell.OffsetX;
            }
            if (double.IsInfinity(maxX - minX))
                return 0;
            else
                return maxX - minX;
        }

        //public bool RemoveCell(ModelCell cell)
        //{
        //    List<ModelCell> listForRemove = null;
        //    ModelCell cellToRemove = null;

        //    foreach (List<ModelCell> row in this.cells)
        //        foreach (ModelCell _cell in row)
        //            if (_cell == cell)
        //            {
        //                listForRemove = row;
        //                break;
        //            }
        //    if (listForRemove != null && cellToRemove != null)
        //    {
        //        listForRemove.Remove(cellToRemove);
        //        return true;
        //    }
        //    else
        //        return false;
        //}


        public void RemoveCell(int horizontalIndex, int verticalIndex)
        {
            throw new NotImplementedException();
        }

        public void ExchangeCells(ModelCell first, ModelCell second)
        {
            throw new NotImplementedException();
        }
    }
}
